import os
import sys

from command_parser.option_filter_base import FilterBase
from command_parser.option_context import OptionContext
from command_parser.option_base import *

class LDFilter(FilterBase):
    
    def __init__(self, context=None):
        self.context = context
        self.__libs_path = []
        self.__sysroot = ""
        self.__default_filter_libs = ['gcc', 'gcc_s', 'stdc++', 'dl', 'c', 'm', 'pthread', 'rt']
        self.__default_dymamic_link = True
        
    def update_search_paths(self, cwd="", compiler="", options=[], option=None):
        
        # first load path from environment LIBRARY_PATH/ LD_LIBRARY_PATH
        
        option_handler_dict = {
            "-L": self.handle_libpath_option,
            "-library-path": self.handle_libpath_option,
            "--library-path": self.handle_libpath_option,
            "-rpath-link": self.handle_libpath_option,
            "--rpath-link": self.handle_libpath_option,
            
            "-sysroot": self.handle_sysroot_option,
            "--sysroot": self.handle_sysroot_option
        }
        
        self.filter_func_callback(options=options, func_dict=option_handler_dict)
            
    def handle_orignal_options(self, cwd="", compiler="", options=[], option=None):
        if not options:
            return
        
        option_handler_dict = {
            "-a": self.handle_a_option,
            
            "-N": self.handle_bstatic_option,
            "--omagic": self.handle_bstatic_option,
            "-n": self.handle_bstatic_option,
            "--nmagic": self.handle_bstatic_option,
            "-i": self.handle_bstatic_option,
            "-r": self.handle_bstatic_option,
            "--relocateable": self.handle_bstatic_option,
            "-Ur": self.handle_bstatic_option,
            "-Bstatic": self.handle_bstatic_option,
            "dn": self.handle_bstatic_option,
            "-non_shared": self.handle_bstatic_option,
            "-static": self.handle_bstatic_option,
            
            "-Bdynamic": self.handle_bdynamic_option,
            "dy": self.handle_bdynamic_option,
            "-call_shared": self.handle_bdynamic_option,
            
            "-l": self.handle_inclib_option,
            "--library": self.handle_inclib_option,
        }
        
        self.filter_func_callback(cwd=cwd, options=options, func_dict=option_handler_dict)
        
    def append_maple_link_option(self, cwd="", compiler="", options=[], option=None):
        if not options:
            raise Exception("It occurs fails when append_maple_link_option")
        
        new_opt = Option(option="-wpaa", type=PREFIX_SIMPLE)
        options.append(new_opt)
    
    def handle_a_option(self, cwd="", compiler="", options=[], option=None):
        if not option:
            return
        
        handler_dict = {
            "archive": self.handle_bstatic_option,
            "default": self.handle_bdynamic_option,
            "shared": self.handle_bdynamic_option
        }
        
        keyword = option.parameter[0]
        func = handler_dict.get(keyword, None)
        if func:
            func(cwd, compiler, options, option)
    
    def handle_bstatic_option(self, cwd="", compiler="", options=[], option=None):
        self.__default_dymamic_link = False
        
    def handle_bdynamic_option(self, cwd="", compiler="", options=[], option=None):
        self.__default_dymamic_link = True
    
    def handle_libpath_option(self, cwd="", compiler="", options=[], option=None):
        if not option:
            return 
        
        libs_paths = option.parameter
        self.__libs_path.extend(libs_paths)
    
    def handle_sysroot_option(self, cwd="", compiler="", options=[], option=None):
        if not option:
            return 
        
        sysroot = option.parameter[0]
        self.__sysroot = sysroot
    
    def handle_inclib_option(self, cwd="", compiler="", options=[], option=None):
        
        if not option:
            return 
        
        # system libs, we should filter it first
        if option.parameter[0] in self.__default_filter_libs:
            return
        
        # we need filter the libs in these search path
        default_search_path = ['/usr/local/lib', '/usr/lib', '/usr/lib32', '/usr/lib64', '/lib', '/lib32', '/lib64']
        
        if self.__sysroot:
            default_search_path = [os.path.join(self.__sysroot, path[1:]) for path in default_search_path]
        
        # search libs in local search path    
        local_search_paths  = self.__libs_path
        lib_name_prefix = "lib" + option.parameter[0]
        
        static_lib_name = lib_name_prefix + ".a"
        dynamic_lib_name = lib_name_prefix + ".so"
        
        real_lib_path = ""
        
        for local_path in local_search_paths:
            if not os.path.isabs(local_path):
                local_path = os.path.join(cwd, local_path)
            
            is_system_path = False
            for system_path in default_search_path:
                if os.path.normpath(local_path).startswith(system_path):
                    is_system_path = True
                    break
            
            # if the local_path in default search path, we need filter it
            if is_system_path:
                continue
            
            static_lib_path = os.path.join(local_path, static_lib_name)
            dynamic_lib_path = os.path.join(local_path, dynamic_lib_name)
            
            if self.__default_dymamic_link:
                if os.path.exists(dynamic_lib_path):
                    real_lib_path = dynamic_lib_path
                    break
                    
                if os.path.exists(static_lib_path):
                    real_lib_path = static_lib_path
                    break
            
            if not self.__default_dymamic_link:
                if os.path.exists(static_lib_path):
                    real_lib_path = static_lib_path
                    break
                
                if os.path.exists(dynamic_lib_path):
                    real_lib_path = dynamic_lib_path
                    break
                
        if real_lib_path:
            option.option = ""
            option.parameter = [os.path.normpath(real_lib_path)]
            option.type = PREFIX_MATCH
            option.keep = True 